#pragma once

#include <iostream>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>

namespace Udp_Server
{
    using func_t = std::function<std::string(const std::string &)>;
    class UdpServer
    {
    public:
        // UdpServer(char IP[17], uint16_t port)
        UdpServer(uint16_t port, func_t func)
            : _sockfd(-1), _port(port), _func(func)
        {
            // memcpy(_IP, IP, strlen(IP));
        }
        void Init()
        {
            // 1.创建套接字
            _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
            if (_sockfd < 0)
            {
                std::cout << "socket error" << std::endl;
                exit(1);
            }
            // 2.绑定socket信息,IP和端口号
            // 2.1 填充sockaddr_in结构体
            struct sockaddr_in s_server;
            // 清零
            memset((void *)&s_server, 0, sizeof(s_server));
            // bzero(&s_server, sizeof(s_server));
            //  IPv4
            s_server.sin_family = AF_INET;
            // 端口号
            //  本地格式->网络序列
            s_server.sin_port = htons(_port);
            // IP
            //  本地格式->网络序列
            //  1. IP转成4字节 2. 4字节转成网络序列 -> in_addr_t inet_addr(const char *cp);
            // local.sin_addr.s_addr = inet_addr(_ip.c_str()); // TODO
            // s_server.sin_addr.s_addr = inet_addr(_IP);

            // 不使用固定的IP
            s_server.sin_addr.s_addr = INADDR_ANY;

            // 结构体大小

            // 2.2 绑定
            int ret = bind(_sockfd, (struct sockaddr *)&s_server, sizeof(s_server));
            if (ret == -1)
            {
                std::cout << "bind error" << std::endl;
                exit(1);
            }
        }

        void Start()
        {
            // 1.运行状态,存储缓冲区，接收对方IP和端口号的结构体
            _run = true;
            char buffer[1024];
            memset((void *)buffer, 0, sizeof(buffer));
            struct sockaddr_in s_clinet;
            socklen_t l_clinet = sizeof(s_clinet);
            // char ser_ret[] = "server recrive ...";
            //  2.收发数据
            while (1)
            {
                // 3.接收信息
                //std::cout << "对象启动成功" << std::endl;

                ssize_t receive_ret = recvfrom(_sockfd, (void *)buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&s_clinet, &l_clinet);
                if (receive_ret > 0)
                {
                    // 4.收到消息,获得发消息的IP和端口号
                    uint16_t clinet_port = ntohs(s_clinet.sin_port);
                    char *clinet_ip = inet_ntoa(s_clinet.sin_addr);
                    // 添加'\0'
                    buffer[receive_ret] = 0;
                    std::cout << clinet_ip << ": " << clinet_port << ": " << buffer << std::endl;
                    // 5.任务处理
                    std::string result = _func(buffer);
                    // 5.发消息
                    ssize_t send_ret = sendto(_sockfd, result.c_str(), result.size(), 0, (struct sockaddr *)&s_clinet, l_clinet);
                    if (send_ret == -1)
                    {
                        std::cout << "sendto error" << std::endl;
                    }
                }
            }
        }

    private:
        int _sockfd; // 套接字描述符
        // char _IP[17] = {0}; // IP地址
        uint16_t _port;    // 端口号
        bool _run = false; // 是否运行中

        func_t _func;
    };

}

// memset
// memcpy
// bzero
// htons
// inet_addr
// recvfrom
// ntohs
// inet_ntoa
// sendto
// stoi
// getline